﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Collections;
using System.Collections.Specialized;
using MeTV.MediaPortalService;
using MeTV.Properties;

// TODO
// Deinterlace

// TODO: later
// Scheduled recording dialog
// When device is used
// Time

namespace MeTV
{
    public partial class MainForm : Form
    {
        WebTvServerUser user;
        DateTime epgStartTime = DateTime.Now;
        Image currentChannelImage = Image.FromFile("Play.png").GetThumbnailImage(24, 24, null, IntPtr.Zero);
        Image recordImage = Image.FromFile("Record.png").GetThumbnailImage(24, 24, null, IntPtr.Zero);
        Player player = new Player();

        ChannelManager channels = new ChannelManager();

        public MainForm()
        {
            InitializeComponent();

            player.SetWindowHandle(panelVideo);
        }        

        private void MainForm_Load(object sender, EventArgs e)
        {
            HijackTimeshift();

            LoadChannels();
            ScheduleManager.Instance.Load();
            UpdateUI();

            if (user != null)
            {
                PlayChannel(channels.GetByChannelID(user.idChannel));
            }
            else if (channels.First != null)
            {
                PlayChannel(channels.First);
            }

            tableLayoutPanelEpg.Focus();

            new System.Threading.Timer(delegate { LoadChannels(); }, null, 60000, 60000);
        }

        void SetWindowSubTitle(string text)
        {
            if (string.IsNullOrEmpty(text))
            {
                text = "It's TV for me computer";
            }

            Text = "Me TV - " + text;
        }

        void LoadChannels()
        {
            lock (channels)
            {
                WebChannelGroup[] groups = Client.Instance.client.GetTvChannelGroups();
                WebChannelGroup selectedGroup = groups[0];
                WebChannel[] webChannels = Client.Instance.client.GetChannelsInTvGroup(selectedGroup.idGroup).OrderBy(x => x.displayName).ToArray();

                foreach (WebChannel webChannel in webChannels)
                {
                    Channel channel = new Channel();
                    channel.WebChannel = webChannel;
                    channel.Programs = GetEpgEventsForChannel(webChannel,
                        DateTime.Now.AddDays(-1), DateTime.Now.AddDays(7));
                    channels.Add(channel);
                }
            }

            UpdateUI();
        }

        void programButton_Click(object sender, EventArgs e)
        {
            WebProgram program = (sender as Button).Tag as WebProgram;
            MessageBox.Show(this,
                string.Format("{0}\n\n{1}", program.Title, program.description, program),
                "Me TV - Program Dialog", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        void channelButton_CheckedChanged(object sender, EventArgs e)
        {
            PlayChannel((sender as RadioButton).Tag as Channel);
            UpdateUI();
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            StopPlayback();
        }

        void HijackTimeshift()
        {
            WebTvServerStatus[] statuses = Client.Instance.client.GetTvServerStatus();
            foreach (WebTvServerStatus status in statuses)
            {
                if (status.status == 1)
                {
                    user = new WebTvServerUser()
                    {
                        idCard = status.idCard,
                        idChannel = status.idChannel,
                        name = status.userName
                    };

                    return;
                }
            }
        }

        void DrawEpg(DateTime startTime)
        {
            lock (channels)
            {
                tableLayoutPanelEpg.SuspendLayout();
                tableLayoutPanelEpg.SuspendDrawing();
                tableLayoutPanelEpg.RowStyles.Clear();
                tableLayoutPanelEpg.ColumnStyles.Clear();
                tableLayoutPanelEpg.Controls.Clear();
                tableLayoutPanelEpg.RowCount = channels.Count;
                tableLayoutPanelEpg.ColumnCount = 1 + (Settings.Default.EpgSpan * 12);
                DateTime endTime = startTime.AddHours(Settings.Default.EpgSpan);

                int rowIndex = 0;
                foreach (Channel channel in channels)
                {
                    RadioButton channelButton = new RadioButton()
                    {
                        Text = channel.Name,
                        Tag = channel,
                        Appearance = Appearance.Button,
                        AutoSize = true,
                        Dock = DockStyle.Fill,
                        Font = new Font(Font, FontStyle.Bold),
                        ImageAlign = ContentAlignment.MiddleRight,
                        TextImageRelation = TextImageRelation.TextBeforeImage
                    };

                    if (user != null && channel.ID == user.idChannel)
                    {
                        channelButton.Image = currentChannelImage;
                    }

                    channelButton.CheckedChanged += new EventHandler(channelButton_CheckedChanged);
                    tableLayoutPanelEpg.Controls.Add(channelButton, 0, rowIndex);

                    int lastEndOffset = 0;
                    IEnumerable<WebProgram> programs = channel.Programs.Where(x => x.startTime < endTime && x.endTime > startTime);
                    foreach (WebProgram program in programs)
                    {
                        int startOffset = Math.Max(0, (int)((program.startTime - epgStartTime).TotalMinutes / 5)) + 1;
                        int duration = (int)((program.endTime - program.startTime).TotalMinutes);
                        int programSpan = duration / 5;
                        int endOffset = startOffset + programSpan;

                        int distanceToPrevious = startOffset - lastEndOffset;
                        if (distanceToPrevious <= 0)
                        {
                            startOffset -= distanceToPrevious;
                            programSpan += distanceToPrevious;
                        }

                        int distanceToLast = tableLayoutPanelEpg.ColumnCount - endOffset;
                        if (distanceToLast < 0)
                        {
                            programSpan += distanceToLast;
                        }

                        if (programSpan >= 1)
                        {
                            lastEndOffset = endOffset;

                            Button programButton = new Button()
                            {
                                Text = GetProgramButtonText(program),
                                AutoSize = true,
                                AutoSizeMode = AutoSizeMode.GrowAndShrink,
                                Tag = program,
                                TextAlign = ContentAlignment.TopLeft,
                                ImageAlign = ContentAlignment.MiddleRight,
                                TextImageRelation = TextImageRelation.TextBeforeImage,
                                Dock = DockStyle.Fill
                            };

                            if (ScheduleManager.Instance.IsScheduled(program))
                            {
                                programButton.Image = recordImage;
                            }

                            programButton.Click += new EventHandler(programButton_Click);
                            programButton.MouseDown += new MouseEventHandler(programButton_MouseDown);
                            tableLayoutPanelEpg.Controls.Add(programButton, startOffset, rowIndex);

                            if (programSpan > 1)
                            {
                                tableLayoutPanelEpg.SetColumnSpan(programButton, programSpan);
                            }
                        }

                    }
                    rowIndex++;
                }

                tableLayoutPanelEpg.ResumeDrawing();
                tableLayoutPanelEpg.ResumeLayout();
            }
        }

        void UpdateUI()
        {
            DrawEpg(epgStartTime);
        }

        void programButton_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right)
            {
                WebProgram program = (sender as Button).Tag as WebProgram;
                WebSchedule[] schedules = ScheduleManager.Instance.GetSchedules(program);
                if (schedules.Length > 0)
                {
                    foreach (WebSchedule schedule in schedules)
                    {
                        Client.Instance.client.DeleteSchedule(schedule.idSchedule);
                    }
                }
                else
                {
                    Client.Instance.client.AddSchedule(program.idChannel, program.Title, program.startTime.AddMinutes(-5), program.endTime.AddMinutes(5), 1);
                }
                ScheduleManager.Instance.Load();
                UpdateUI();
            }
        }

        string GetProgramButtonText(WebProgram program)
        {
            return program == null ? "Not available" : string.Format("{1} - {2}\n{0}",
                program.Title, program.startTime.ToShortTimeString(),
                program.endTime.ToShortTimeString());
        }

        private void PlayChannel(Channel channel)
        {
            StopPlayback();
            WebTvResult tvResult = Client.Instance.client.StartTimeShifting(channel.ID);

            if (tvResult.result != 0)
            {
                throw new Exception(string.Format("Failed to start timeshifting: {0}", tvResult.result));
            }

            user = tvResult.user;
            player.Play(tvResult.rtspURL);
            TopMost = true;

            SetWindowSubTitle(string.Format("{0} - {1}", channel.Name, channel.CurrentEpgEventTitle));
        }

        WebProgram[] GetEpgEventsForChannel(WebChannel channel, DateTime from, DateTime to)
        {
            return Client.Instance.client.GetEPGForChannel(
                channel.idChannel.ToString(),
                from.AddDays(-1).ToString(),
                to.AddDays(1).ToString()
            ).Where(x => x.endTime > from && x.startTime < to).ToArray();
        }

        private void StopPlayback()
        {
            TopMost = false;
            player.Stop();

            if (user != null)
            {
                Client.Instance.client.StopTimeShifting(user.idChannel, user.idCard, user.name);
                user = null;
            }
        }

        private void panelOverlay_MouseClick(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Right)
            {
                splitContainerMain.Panel2Collapsed = !splitContainerMain.Panel2Collapsed;

                if (!splitContainerMain.Panel2Collapsed)
                {
                    tableLayoutPanelEpg.Focus();
                }
            }
        }

        private void panelOverlay_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            if (e.Button == MouseButtons.Left)
            {
                if (WindowState != FormWindowState.Maximized)
                {
                    splitContainerMain.Panel2Collapsed = true;
                    FormBorderStyle = FormBorderStyle.None;
                    WindowState = FormWindowState.Maximized;
                }
                else
                {
                    FormBorderStyle = FormBorderStyle.Sizable;
                    WindowState = FormWindowState.Normal;
                }
            }
        }

        private void buttonNow_Click(object sender, EventArgs e)
        {
            epgStartTime = DateTime.Now;
            UpdateUI();
        }

        private void buttonNext_Click(object sender, EventArgs e)
        {
            epgStartTime = epgStartTime.AddHours(Settings.Default.EpgSpan);
            UpdateUI();
        }

        private void buttonNextDay_Click(object sender, EventArgs e)
        {
            epgStartTime = epgStartTime.AddDays(1);
            UpdateUI();
        }

        private void buttonPreviousDay_Click(object sender, EventArgs e)
        {
            epgStartTime = epgStartTime.AddDays(-1);
            UpdateUI();
        }

        private void buttonPrevious_Click(object sender, EventArgs e)
        {
            epgStartTime = epgStartTime.AddHours(-Settings.Default.EpgSpan);
            UpdateUI();
        }

        private void buttonSearch_Click(object sender, EventArgs e)
        {
            EpgSearchForm form = new EpgSearchForm();
            form.ShowDialog(this);
            UpdateUI();
        }
    }
}
